package com.jh.fcsm.controller.sys;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.jh.fcsm.common.BaseController;
import com.jh.fcsm.common.RestApiResponse;
import com.jh.fcsm.common.exception.ServiceException;
import com.jh.fcsm.common.redis.RedisUtil;
import com.jh.fcsm.constant.Constant;
import com.jh.fcsm.constant.RedisConstant;
import com.jh.fcsm.util.security.UUIDUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 验证码 Controller
 *
 * @author szx
 * @date 2022-03-22
 */
@RestController
@RequestMapping("/sys/captcha")
@Api(value = "图形验证码", tags = "图形验证码")
public class CaptchaController extends BaseController {

    @Autowired
    private DefaultKaptcha captchaProducer;
    @Autowired
    private RedisUtil redisUtil;

    @GetMapping("/getCode")
    @ApiOperation(value = "获取图形验证码")
    public RestApiResponse<?> getCode() {
        Map<String, String> base64img = getCaptchaCode();
        return RestApiResponse.ok(base64img);
    }

    @GetMapping("/checkLoginKaptcha")
    @ApiOperation(value = "校验登录图形验证码")
    public RestApiResponse<?> checkLoginKaptcha(@RequestParam(value = "kaptcha") String kaptcha, @RequestParam(value = "random") String random) {
        return checkCode(kaptcha, random);
    }

    /**
     * 获取图形验证
     *
     * @return
     */
    private Map<String, String> getCaptchaCode() {
        Map<String, String> result = new HashMap<>();
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            // 生产验证码字符串
            String createText = captchaProducer.createText();
            // 使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
            BufferedImage challenge = captchaProducer.createImage(createText);
            ImageIO.write(challenge, "jpg", os);
            // 把验证码和随机字符串保存到redis中然后把随机字符串和验证码图片以base64传到前台
            String guid = UUIDUtils.getUUID();
            // 将验证码文本值保存到redis
            redisUtil.set(RedisConstant.VALID_CODE_KEY + guid, createText, RedisConstant.REDIS_EXPIRE_ONE_MIN);
            // 将guid响应给前端
            result.put("random", guid);
        } catch (Exception e) {
            throw new ServiceException("验证码生成失败，请刷新");
        }
        result.put("img", Base64.getEncoder().encodeToString(os.toByteArray()));
        return result;
    }

    /**
     * 校验用户输入验证码是否正确
     *
     * @param code   用户输入验证码
     * @param random 生成验证唯一标识
     * @return
     */
    private RestApiResponse<?> checkCode(String code, String random) {
        if (StringUtils.isEmpty(random)) {
            return RestApiResponse.error("非法请求！");
        }
        // 页面输入的验证码
        if (StringUtils.isEmpty(code)) {
            return RestApiResponse.error("验证码为空!");
        }
        // 正确的图形验证码
        String key = RedisConstant.VALID_CODE_KEY + random;
        String validateCode = (String) redisUtil.get(key);
        if (StringUtils.isEmpty(validateCode)) {
            return RestApiResponse.error("验证码过期请刷新!");
        }
        logger.info("服务器图形验证码:" + validateCode);
        logger.info("用户输入图形验证码:" + code);
        if (StringUtils.isEmpty(validateCode)) {
            return RestApiResponse.error("验证码错误，请刷新后重试!");
        }
        // 如果验证码合法，则生成重新生成一个有效期5s的uuid保存到redis，并响应给前台。如果前台5s未登录则需要重新获取验证码
        if (validateCode.equalsIgnoreCase(code)) {
            redisUtil.del(key);
            String guid = UUIDUtils.getUUID();
            redisUtil.set(RedisConstant.VALID_CODE_KEY + guid, Constant.YES, RedisConstant.REDIS_EXPIRE_VALID);
            return RestApiResponse.ok(guid);
        } else {
            return RestApiResponse.error("验证码错误!");
        }
    }

}